package main

import (
	"database/sql"
	"fmt"
	"net/http"
	"regexp"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func CheckErrReturn(msg string, err error) bool {
	if err != nil {
		fmt.Println(msg, err)
		//painc(err)
		return false
	}
	return true
}

func CheckErr(msg string, err error) {
	if err != nil {
		fmt.Println(msg, err)
		panic(err)

	}
}

const (
	USERNAME = "root"
	PASSWORD = "123456"
	HOST     = "172.16.6.78"
	PORT     = "3306"
	DBNAME   = "t"
)

//定义db
var DB *sql.DB

type MovieData struct {
	Title    string `json:"title"`
	Director string `json:"director"`
	Picture  string `json:"picture"`
	Actor    string `json:"actor"`
	Year     string `json:"year"`
	Score    string `json:"score"`
	Quote    string `json:"quote"`
}

func main() {
	InitDB()

	for i := 0; i < 10; i++ {
		fmt.Printf("正在爬取第%d页信息\n", i)
		Spider(strconv.Itoa(i * 25))
	}

}

func Spider(page string) {
	fmt.Println(page)

	// 发送请求
	client := http.Client{}

	req, err := http.NewRequest("GET", "https://movie.douban.com/top250?start="+page, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	//构造header
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Cache-Control", "max-age=0")
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
	req.Header.Set("Sec-Fetch-Site", "same-origin")
	req.Header.Set("Sec-Fetch-Mode", "navigate")
	req.Header.Set("Sec-Fetch-User", "?1")
	req.Header.Set("Sec-Fetch-Dest", "document")
	req.Header.Set("Referer", "https://movie.douban.com/chart")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")

	//发送请求并且获取response
	resp, err := client.Do(req)

	if err != nil {
		fmt.Println("请求失败", err)
		return
	}

	defer resp.Body.Close()

	//解析页面
	docDetail, err := goquery.NewDocumentFromReader(resp.Body)

	if err != nil {
		fmt.Println("解析失败", err)
	}
	//<span class="title">肖申克的救赎</span>
	//#content > div > div.article > ol > li:nth-child(1)

	//先找到电影信息的dom主干
	title := docDetail.Find("#content > div > div.article > ol > li").
		Each(func(i int, s *goquery.Selection) { //子元素继续遍历，这是个匿名函数，i是什么意思？
			var MovieData MovieData
			title := s.Find("div.info > div.hd > a > span:nth-child(1)").Text()
			img := s.Find("div.pic > a > img")
			imgTmp, ok := img.Attr("src")
			info := strings.Trim(s.Find("div.info > div.bd > p:nth-child(1)").Text(), " ")
			director, actor, year := InfoSpite(info)
			score := strings.Trim(s.Find("div.info > div.bd > div > span.rating_num").Text(), " ")
			//score = strings.Trim(score, "\n")
			quote := strings.Trim(s.Find("div.info > div.bd > p.quote > span").Text(), " ")

			if ok {
				fmt.Println("title:", title)
				fmt.Println("img:", img)
				fmt.Println("imgTmp:", imgTmp)
				fmt.Println("director:", director)
				fmt.Println("actor:", actor)
				fmt.Println("year:", year)
				fmt.Println("score:", score)
				fmt.Println("quote:", quote)
				MovieData.Title = title
				MovieData.Director = director
				MovieData.Picture = imgTmp
				MovieData.Actor = actor
				MovieData.Year = year
				MovieData.Score = score
				MovieData.Quote = quote
				fmt.Println("Moviedata:", MovieData)
				InsertSql(MovieData)

			}

		})
	fmt.Println("title", title)

}

//正则获取主演，演员，年份等信息
func InfoSpite(info string) (director, actor, year string) {
	directorRe, _ := regexp.Compile(`导演:(.*)主演:`)
	director = string(directorRe.Find([]byte(info)))

	actorRe, _ := regexp.Compile(`主演:(.*)`)

	actor = string(actorRe.Find([]byte(info)))

	yearRe, _ := regexp.Compile(`(\d+)`)
	year = string(yearRe.Find([]byte(info)))
	//fmt.Println(director, actor, year)
	return
}

func InitDB() {
	path := strings.Join([]string{USERNAME, ":", PASSWORD, "@tcp(", HOST, ":", PORT, ")/", DBNAME, "?charset=utf8mb4"}, "")
	fmt.Println(path)
	DB, _ = sql.Open("mysql", path)
	DB.SetConnMaxLifetime(10)
	DB.SetMaxIdleConns(5)
	if err := DB.Ping(); err != nil {
		fmt.Println("open database fail")
		return
	}
	fmt.Println("connect success")
}

func InsertSql(MovieData MovieData) bool {
	tx, err := DB.Begin()
	/*
		if err != nil {
			fmt.Println("tx fail")
			return false

		}
	*/
	msg := "tx fail"
	CheckErr(msg, err)

	// tx 是事务

	// Prepare creates a prepared statement for use within a transaction.

	stmt, err := tx.Prepare("Insert INTO movie_data(`Title`,`Director`,`Picture`,`Actor`,`Year`,`Score`,`Quote`) VALUES (?,?,?,?,?,?,?)")

	msg = "Prepare fail"
	CheckErr(msg, err)

	_, err = stmt.Exec(MovieData.Title, MovieData.Director, MovieData.Picture, MovieData.Actor, MovieData.Year, MovieData.Score, MovieData.Quote)

	msg = "Exec sql fail"
	CheckErr(msg, err)

	_ = tx.Commit()
	return true

}

/*
db使用
导库

"database/sql"
_ "github.com/jinzhu/gorm/dialects/mysql"

//定义db变量
var DB *sql.DB

//连接
DB, _ = sql.Open("mysql", path)

//获取事务
	tx, err := DB.Begin()

//事务语句准备
 tx.Prepare

// 语句执行
stmt.Exec

// 提交
commit



*/
